package com.culturexx.core.utils;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class HibernateUtils {

    private static final Logger log = LoggerFactory.getLogger(HibernateUtils.class);
    private static SessionFactory sessionFactory = null;
    //SessionFactory和Configuration对整个应用来说，只有一个实例存在
    //为用户访问定义了一个本地线程变量，是静态的，对每一个访问该线程的用户产生一个实例
    private static final ThreadLocal<Session> threadlocal = new ThreadLocal<Session>();


    public static void init() {
        try {
            Configuration cfg = new Configuration().configure();
            sessionFactory = cfg.buildSessionFactory();

        } catch (Exception e) {
            log.error("创建会话工厂失败");
            e.printStackTrace();
        }
    }

    //要取得Session对象时，首先从当前用户的线程取得Session对象。
    //如果还没有创建，从SessionFactory中创建一个Session
    //此时会判断SessionFactory对象是否已经创建
    //过程：
    //首先判断threadLocal中是否存在Session对象
    // 如果不存在 则创建Session对象
    // 在创建Session对象时 首先要判断系统是否已经加载Configuration
    // 如果没有sessionFactory 则需要先创建该对象
    // 创建完成的Session对象 需要保存在threadLocal中以供本次访问线程的下一次调用
    public static Session getSession() throws HibernateException {
        Session session = (Session) threadlocal.get();
        if (session == null || !session.isOpen()) {
            if (sessionFactory == null) {
                rebulidSessionFactory();
            }
            session = (sessionFactory != null) ? sessionFactory.openSession() : null;
            threadlocal.set(session);
        }
        return session;
    }

    private static void rebulidSessionFactory() {
        try {
            Configuration cfg = new Configuration().configure();
            sessionFactory = cfg.buildSessionFactory();
        } catch (Exception e) {
            log.error("创建会话工厂失败");
            e.printStackTrace();
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    //  在关闭Session对象是 只需要从当前线程中取得Session对象 关闭该对象 并置空本地线程变量即可
    public static void closeSession() throws HibernateException {
        Session session = (Session) threadlocal.get();
        threadlocal.set(null);
        if (session != null) {
            session.close();
        }
    }
}
